/*
 * Copyright (c) 2022-2022 All rights Reserved.
 */

package com.driving.core.base;

import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Map;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.driving.core.exception.DrivingException;
import com.driving.core.mapper.IAdminMapper;
import com.driving.core.mapper.ICoachMapper;
import com.driving.core.mapper.IStudentMapper;
import com.driving.core.util.ConfigReader;
import com.driving.core.util.Constant;
import com.driving.core.util.Constant.Audience;
import com.driving.core.util.JsonWebToken;
import com.driving.core.util.MessageType.ExceptionType;
import com.driving.core.util.PasswordEncryption;

import lombok.extern.slf4j.Slf4j;

/**
 * 基础服务实现，对ServiceImpl的扩展，同时实现IBaseService
 *
 * @param <M> 数据操作对象
 * @param <T> 需要操作的数据对象
 * @author SAGITTAR
 * @since 2017
 * @see ServiceImpl
 * @see IService
 * @see IBaseService
 */
@Slf4j
public abstract class BaseServiceImpl<M extends IBaseMapper<T>, T extends AbstractModel<T>> extends ServiceImpl<M, T>
        implements IBaseService<T> {

    @Autowired
    protected ConfigReader configReader;

    /**
     * 验证密码的正确性
     *
     * @param dtoPassword 用户输入，明文
     * @param encryption 加密密码，密文
     * @return 验证密码的正确性
     */
    protected boolean validatePassword(String dtoPassword, String encryption) {
        boolean result;
        try {
            result = PasswordEncryption.authenticate(dtoPassword, encryption);
        } catch (GeneralSecurityException e) {
            throw new DrivingException(e);
        }
        return result;
    }

    /**
     * 根据token或mobile获取相应的个人编号
     *
     * @param personMapper 对应的操作对象
     * @param token token
     * @param mobile mobile
     * @param oldPassword oldPassword
     * @return 根据token或mobile获取相应的个人编号
     */
    protected <P extends AbstractPerson<P>> int getCorrespondingIdByTokenOrMobile(IPersonMapper<P> personMapper,
            String token, String mobile, String oldPassword) {
        Audience audience = null;
        // 判断身份类型
        if (personMapper instanceof IStudentMapper) {
            audience = Audience.STUDENT;
        }
        if (personMapper instanceof ICoachMapper) {
            audience = Audience.COACH;
        }
        if (personMapper instanceof IAdminMapper) {
            audience = Audience.ADMIN;
        }
        Map<String, String> correspondingMap = JsonWebToken.parse(token, audience);
        // 登录状态或token未过期
        if (Objects.isNull(correspondingMap)) {
            if (StringUtils.isBlank(mobile)) {
                throw new DrivingException(configReader.getExceptionMessage(ExceptionType.NOT_COMPLETE));
            }
            AbstractPerson<P> previous = personMapper.selectByMobile(mobile);
            // 手机号不存在
            if (Objects.isNull(previous)) {
                throw new DrivingException(configReader.getExceptionMessage(ExceptionType.USER_NOT_FOUND));
            }
            return previous.getId();
        }
        // 判断旧密码正误
        try {
            if (!PasswordEncryption.authenticate(oldPassword, correspondingMap.get(Constant.PASSWORD))) {
                throw new DrivingException(configReader.getExceptionMessage(ExceptionType.INCORRECT_OLD_PASSWORD));
            }
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            log.error(e.getLocalizedMessage(), e);
            throw new DrivingException(e);
        }
        return Integer.parseInt(correspondingMap.get(Constant.ID));
    }
}
